home *** CD-ROM | disk | FTP | other *** search
/ Whiteline: Alpha / Whiteline Alpha.iso / linux / atari / source / source.lzh / atari-linux-0.01pl3 / fs / msdos / misc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-05  |  13.7 KB  |  537 lines

  1. /*
  2.  *  linux/fs/msdos/misc.c
  3.  *
  4.  *  Written 1992,1993 by Werner Almesberger
  5.  */
  6.  
  7. #include <linux/fs.h>
  8. #include <linux/msdos_fs.h>
  9. #include <linux/sched.h>
  10. #include <linux/kernel.h>
  11. #include <linux/errno.h>
  12. #include <linux/string.h>
  13. #include <linux/stat.h>
  14.  
  15. /* Well-known binary file extensions */
  16.  
  17. static char bin_extensions[] =
  18.   "EXECOMBINAPPSYSDRVOVLOVROBJLIBDLLPIF"    /* program code */
  19.   "ARCZIPLHALZHZOOTARZ  ARJ"    /* common archivers */
  20.   "TZ TAZTZPTPZ"        /* abbreviations of tar.Z and tar.zip */
  21.   "GIFBMPTIFGL JPGPCX"        /* graphics */
  22.   "TFMVF GF PK PXLDVI";        /* TeX */
  23.  
  24.  
  25. /*
  26.  * fs_panic reports a severe file system problem and sets the file system
  27.  * read-only. The file system can be made writable again by remounting it.
  28.  */
  29.  
  30. void fs_panic(struct super_block *s,char *msg)
  31. {
  32.     int not_ro;
  33.  
  34.     not_ro = !(s->s_flags & MS_RDONLY);
  35.     if (not_ro) s->s_flags |= MS_RDONLY;
  36.     printk("Filesystem panic (dev 0x%04X, mounted on 0x%04X:%ld)\n  %s\n",
  37.         s->s_dev,s->s_covered->i_dev,s->s_covered->i_ino,msg);
  38.     if (not_ro)
  39.         printk("  File system has been set read-only\n");
  40. }
  41.  
  42.  
  43. /*
  44.  * is_binary selects optional text conversion based on the conversion mode and
  45.  * the extension part of the file name.
  46.  */
  47.  
  48. int is_binary(char conversion,char *extension)
  49. {
  50.     char *walk;
  51.  
  52.     switch (conversion) {
  53.         case 'b':
  54.             return 1;
  55.         case 't':
  56.             return 0;
  57.         case 'a':
  58.             for (walk = bin_extensions; *walk; walk += 3)
  59.                 if (!strncmp(extension,walk,3)) return 1;
  60.             return 0;
  61.         default:
  62.             printk("Invalid conversion mode - defaulting to "
  63.                 "binary.\n");
  64.             return 1;
  65.     }
  66. }
  67.  
  68.  
  69. /* File creation lock. This is system-wide to avoid deadlocks in rename. */
  70. /* (rename might deadlock before detecting cross-FS moves.) */
  71.  
  72. static struct wait_queue *creation_wait = NULL;
  73. static creation_lock = 0;
  74.  
  75.  
  76. void lock_creation(void)
  77. {
  78.     while (creation_lock) sleep_on(&creation_wait);
  79.     creation_lock = 1;
  80. }
  81.  
  82.  
  83. void unlock_creation(void)
  84. {
  85.     creation_lock = 0;
  86.     wake_up(&creation_wait);
  87. }
  88.  
  89.  
  90. void lock_fat(struct super_block *sb)
  91. {
  92.     while (MSDOS_SB(sb)->fat_lock) sleep_on(&MSDOS_SB(sb)->fat_wait);
  93.     MSDOS_SB(sb)->fat_lock = 1;
  94. }
  95.  
  96.  
  97. void unlock_fat(struct super_block *sb)
  98. {
  99.     MSDOS_SB(sb)->fat_lock = 0;
  100.     wake_up(&MSDOS_SB(sb)->fat_wait);
  101. }
  102.  
  103.  
  104. /*
  105.  * msdos_add_cluster tries to allocate a new cluster and adds it to the file
  106.  * represented by inode. The cluster is zero-initialized.
  107.  */
  108.  
  109. int msdos_add_cluster(struct inode *inode)
  110. {
  111.     int count,nr,limit,last,current,sector;
  112.     void *data;
  113.     struct buffer_head *bh;
  114.  
  115.     if (inode->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
  116.     if (!MSDOS_SB(inode->i_sb)->free_clusters) return -ENOSPC;
  117.     lock_fat(inode->i_sb);
  118.     limit = MSDOS_SB(inode->i_sb)->clusters;
  119.     nr = limit; /* to keep GCC happy */
  120.     for (count = 0; count < limit; count++) {
  121.         nr = ((count+MSDOS_SB(inode->i_sb)->prev_free) % limit)+2;
  122.         if (fat_access(inode->i_sb,nr,-1) == 0) break;
  123.     }
  124. #ifdef DEBUG
  125. printk("free cluster: %d\n",nr);
  126. #endif
  127.     MSDOS_SB(inode->i_sb)->prev_free = (count+MSDOS_SB(inode->i_sb)->
  128.         prev_free+1) % limit;
  129.     if (count >= limit) {
  130.         MSDOS_SB(inode->i_sb)->free_clusters = 0;
  131.         unlock_fat(inode->i_sb);
  132.         return -ENOSPC;
  133.     }
  134.     fat_access(inode->i_sb,nr,MSDOS_SB(inode->i_sb)->fat_bits == 12 ?
  135.                /* For Atari: The GEMDOS uses 0xffff for a
  136.                 * end-of-file and I've seen programs that can't
  137.                 * deal with other values. I don't even know if
  138.                 * GEMDOS itself could handle EOF's != 0xffff
  139.                 * correctly in all cases. So better use 0xffff.
  140.                 */
  141. #ifdef CONFIG_ATARI
  142.                0xfff : 0xffff);
  143. #else
  144.                0xff8 : 0xfff8);
  145. #endif
  146.     if (MSDOS_SB(inode->i_sb)->free_clusters != -1)
  147.         MSDOS_SB(inode->i_sb)->free_clusters--;
  148.     unlock_fat(inode->i_sb);
  149. #ifdef DEBUG
  150. printk("set to %x\n",fat_access(inode->i_sb,nr,-1));
  151. #endif
  152.     last = 0;
  153.     if ((current = MSDOS_I(inode)->i_start) != 0) {
  154.         cache_lookup(inode,INT_MAX,&last,¤t);
  155.         while (current && current != -1)
  156.             if (!(current = fat_access(inode->i_sb,
  157.                 last = current,-1))) {
  158. #ifdef DEBUG
  159. printk("current = %d\n",current);
  160. #endif
  161.                 fs_panic(inode->i_sb,"File without EOF");
  162.                 return -ENOSPC;
  163.             }
  164.     }
  165. #ifdef DEBUG
  166. printk("last = %d\n",last);
  167. #endif
  168.     if (last) fat_access(inode->i_sb,last,nr);
  169.     else {
  170.         MSDOS_I(inode)->i_start = nr;
  171.         inode->i_dirt = 1;
  172.     }
  173. #ifdef DEBUG
  174. if (last) printk("next set to %d\n",fat_access(inode->i_sb,last,-1));
  175. #endif
  176.     for (current = 0; current < MSDOS_SB(inode->i_sb)->cluster_size;
  177.         current++) {
  178.         sector = MSDOS_SB(inode->i_sb)->data_start+(nr-2)*
  179.             MSDOS_SB(inode->i_sb)->cluster_size+current;
  180. #ifdef DEBUG
  181. printk("zeroing sector %d\n",sector);
  182. #endif
  183.         if (current < MSDOS_SB(inode->i_sb)->cluster_size-1 &&
  184.             !(sector & 1)) {
  185.             if (!(bh = getblk(inode->i_dev,sector >> 1,
  186.                 BLOCK_SIZE)))
  187.                 printk("getblk failed\n");
  188.             else {
  189.                 memset(bh->b_data,0,BLOCK_SIZE);
  190.                 bh->b_uptodate = 1;
  191.             }
  192.             current++;
  193.         }
  194.         else {
  195.             if (!(bh = msdos_sread(inode->i_dev,sector,
  196.                 &data)))
  197.                 printk("msdos_sread failed\n");
  198.             else memset(data,0,SECTOR_SIZE);
  199.         }
  200.         if (bh) {
  201.             bh->b_dirt = 1;
  202.             brelse(bh);
  203.         }
  204.     }
  205.     inode->i_blocks += MSDOS_SB(inode->i_sb)->cluster_size;
  206.     if (S_ISDIR(inode->i_mode)) {
  207.         if (inode->i_size & (SECTOR_SIZE-1)) {
  208.             fs_panic(inode->i_sb,"Odd directory size");
  209.             inode->i_size = (inode->i_size+SECTOR_SIZE) &
  210.                 ~(SECTOR_SIZE-1);
  211.         }
  212.         inode->i_size += SECTOR_SIZE*MSDOS_SB(inode->i_sb)->
  213.             cluster_size;
  214. #ifdef DEBUG
  215. printk("size is %d now (%x)\n",inode->i_size,inode);
  216. #endif
  217.         inode->i_dirt = 1;
  218.     }
  219.     return 0;
  220. }
  221.  
  222.  
  223. /* Linear day numbers of the respective 1sts in non-leap years. */
  224.  
  225. static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
  226.           /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
  227.  
  228.  
  229. extern struct timezone sys_tz;
  230.  
  231.  
  232. /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
  233.  
  234. int date_dos2unix(unsigned short time,unsigned short date)
  235. {
  236.     int month,year,secs;
  237.  
  238.     month = ((date >> 5) & 15)-1;
  239.     year = date >> 9;
  240.     secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
  241.         ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
  242.         month < 2 ? 1 : 0)+3653);
  243.             /* days since 1.1.70 plus 80's leap day */
  244.     secs += sys_tz.tz_minuteswest*60;
  245.     return secs;
  246. }
  247.  
  248.  
  249. /* Convert linear UNIX date to a MS-DOS time/date pair. */
  250.  
  251. void date_unix2dos(int unix_date,unsigned short *time,
  252.     unsigned short *date)
  253. {
  254.     int day,year,nl_day,month;
  255.  
  256.     unix_date -= sys_tz.tz_minuteswest*60;
  257.     *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
  258.         (((unix_date/3600) % 24) << 11);
  259.     day = unix_date/86400-3652;
  260.     year = day/365;
  261.     if ((year+3)/4+365*year > day) year--;
  262.     day -= (year+3)/4+365*year;
  263.     if (day == 59 && !(year & 3)) {
  264.         nl_day = day;
  265.         month = 2;
  266.     }
  267.     else {
  268.         nl_day = (year & 3) || day <= 59 ? day : day-1;
  269.         for (month = 0; month < 12; month++)
  270.             if (day_n[month] > nl_day) break;
  271.     }
  272.     *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
  273. }
  274.  
  275.  
  276. /* Returns the inode number of the directory entry at offset pos. If bh is
  277.    non-NULL, it is brelse'd before. Pos is incremented. The buffer header is
  278.    returned in bh. */
  279.  
  280. int msdos_get_entry(struct inode *dir, off_t *pos,struct buffer_head **bh,
  281.     struct msdos_dir_entry **de)
  282. {
  283.     int sector,offset;
  284.     void *data;
  285.  
  286.     while (1) {
  287.         offset = *pos;
  288.         if ((sector = msdos_smap(dir,offset >> SECTOR_BITS)) == -1)
  289.             return -1;
  290.         if (!sector)
  291.             return -1; /* beyond EOF */
  292.         *pos += sizeof(struct msdos_dir_entry);
  293.         if (*bh)
  294.             brelse(*bh);
  295.         if (!(*bh = msdos_sread(dir->i_dev,sector,&data))) {
  296.             printk("Directory sread (sector %d) failed\n",sector);
  297.             continue;
  298.         }
  299.         *de = (struct msdos_dir_entry *) (data+(offset &
  300.             (SECTOR_SIZE-1)));
  301.         return (sector << MSDOS_DPS_BITS)+((offset & (SECTOR_SIZE-1)) >>
  302.             MSDOS_DIR_BITS);
  303.     }
  304. }
  305.  
  306.  
  307. /*
  308.  * Now an ugly part: this set of directory scan routines works on clusters
  309.  * rather than on inodes and sectors. They are necessary to locate the '..'
  310.  * directory "inode". raw_scan_sector operates in four modes:
  311.  *
  312.  * name     number   ino      action
  313.  * -------- -------- -------- -------------------------------------------------
  314.  * non-NULL -        X        Find an entry with that name
  315.  * NULL     non-NULL non-NULL Find an entry whose data starts at *number
  316.  * NULL     non-NULL NULL     Count subdirectories in *number. (*)
  317.  * NULL     NULL     non-NULL Find an empty entry
  318.  *
  319.  * (*) The return code should be ignored. It DOES NOT indicate success or
  320.  *     failure. *number has to be initialized to zero.
  321.  *
  322.  * - = not used, X = a value is returned unless NULL
  323.  *
  324.  * If res_bh is non-NULL, the buffer is not deallocated but returned to the
  325.  * caller on success. res_de is set accordingly.
  326.  *
  327.  * If cont is non-zero, raw_found continues with the entry after the one
  328.  * res_bh/res_de point to.
  329.  */
  330.  
  331.  
  332. #define RSS_NAME /* search for name */ \
  333.     done = !strncmp(data[entry].name,name,MSDOS_NAME) && \
  334.      !(data[entry].attr & ATTR_VOLUME);
  335.  
  336. #define RSS_START /* search for start cluster */ \
  337.     done = !IS_FREE(data[entry].name) && CF_LE_W(data[entry].start) == *number;
  338.  
  339. #define RSS_FREE /* search for free entry */ \
  340.     { \
  341.     done = IS_FREE(data[entry].name); \
  342.     if (done) { \
  343.         inode = iget(sb,sector*MSDOS_DPS+entry); \
  344.         if (inode) { \
  345.         /* Directory slots of busy deleted files aren't available yet. */ \
  346.         done = !MSDOS_I(inode)->i_busy; \
  347.         iput(inode); \
  348.         } \
  349.     } \
  350.     }
  351.  
  352. #define RSS_COUNT /* count subdirectories */ \
  353.     { \
  354.     done = 0; \
  355.     if (!IS_FREE(data[entry].name) && (data[entry].attr & ATTR_DIR)) \
  356.         (*number)++; \
  357.     }
  358.  
  359. static int raw_scan_sector(struct super_block *sb,int sector,char *name,
  360.     int *number,int *ino,struct buffer_head **res_bh,
  361.     struct msdos_dir_entry **res_de)
  362. {
  363.     struct buffer_head *bh;
  364.     struct msdos_dir_entry *data;
  365.     struct inode *inode;
  366.     int entry,start,done;
  367.  
  368.     if (!(bh = msdos_sread(sb->s_dev,sector,(void **) &data))) return -EIO;
  369.     for (entry = 0; entry < MSDOS_DPS; entry++) {
  370.         if (name) RSS_NAME
  371.         else {
  372.             if (!ino) RSS_COUNT
  373.             else {
  374.                 if (number) RSS_START
  375.                 else RSS_FREE
  376.             }
  377.         }
  378.         if (done) {
  379.             if (ino) *ino = sector*MSDOS_DPS+entry;
  380.             start = CF_LE_W(data[entry].start);
  381.             if (!res_bh) brelse(bh);
  382.             else {
  383.                 *res_bh = bh;
  384.                 *res_de = &data[entry];
  385.             }
  386.             return start;
  387.         }
  388.     }
  389.     brelse(bh);
  390.     return -ENOENT;
  391. }
  392.  
  393.  
  394. /*
  395.  * raw_scan_root performs raw_scan_sector on the root directory until the
  396.  * requested entry is found or the end of the directory is reached.
  397.  */
  398.  
  399. static int raw_scan_root(struct super_block *sb,char *name,int *number,int *ino,
  400.     struct buffer_head **res_bh,struct msdos_dir_entry **res_de)
  401. {
  402.     int count,cluster;
  403.  
  404.     for (count = 0; count < MSDOS_SB(sb)->dir_entries/MSDOS_DPS; count++) {
  405.         if ((cluster = raw_scan_sector(sb,MSDOS_SB(sb)->dir_start+count,
  406.             name,number,ino,res_bh,res_de)) >= 0) return cluster;
  407.     }
  408.     return -ENOENT;
  409. }
  410.  
  411.  
  412. /*
  413.  * raw_scan_nonroot performs raw_scan_sector on a non-root directory until the
  414.  * requested entry is found or the end of the directory is reached.
  415.  */
  416.  
  417. static int raw_scan_nonroot(struct super_block *sb,int start,char *name,
  418.     int *number,int *ino,struct buffer_head **res_bh,struct msdos_dir_entry
  419.     **res_de)
  420. {
  421.     int count,cluster;
  422.  
  423. #ifdef DEBUG
  424.     printk("raw_scan_nonroot: start=%d\n",start);
  425. #endif
  426.     do {
  427.         for (count = 0; count < MSDOS_SB(sb)->cluster_size; count++) {
  428.             if ((cluster = raw_scan_sector(sb,(start-2)*
  429.                 MSDOS_SB(sb)->cluster_size+MSDOS_SB(sb)->data_start+
  430.                 count,name,number,ino,res_bh,res_de)) >= 0)
  431.                 return cluster;
  432.         }
  433.         if (!(start = fat_access(sb,start,-1))) {
  434.             fs_panic(sb,"FAT error");
  435.             break;
  436.         }
  437. #ifdef DEBUG
  438.     printk("next start: %d\n",start);
  439. #endif
  440.     }
  441.     while (start != -1);
  442.     return -ENOENT;
  443. }
  444.  
  445.  
  446. /*
  447.  * raw_scan performs raw_scan_sector on any sector.
  448.  *
  449.  * NOTE: raw_scan must not be used on a directory that is is the process of
  450.  *       being created.
  451.  */
  452.  
  453. static int raw_scan(struct super_block *sb,int start,char *name,int *number,
  454.     int *ino,struct buffer_head **res_bh,struct msdos_dir_entry **res_de)
  455. {
  456.     if (start)
  457.         return raw_scan_nonroot(sb,start,name,number,ino,res_bh,res_de);
  458.     else return raw_scan_root(sb,name,number,ino,res_bh,res_de);
  459. }
  460.  
  461.  
  462. /*
  463.  * msdos_parent_ino returns the inode number of the parent directory of dir.
  464.  * File creation has to be deferred while msdos_parent_ino is running to
  465.  * prevent renames.
  466.  */
  467.  
  468. int msdos_parent_ino(struct inode *dir,int locked)
  469. {
  470.     static int zero = 0;
  471.     int error,current,prev,nr;
  472.  
  473.     if (!S_ISDIR(dir->i_mode)) panic("Non-directory fed to m_p_i");
  474.     if (dir->i_ino == MSDOS_ROOT_INO) return dir->i_ino;
  475.     if (!locked) lock_creation(); /* prevent renames */
  476.     if ((current = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,MSDOS_DOTDOT,
  477.         &zero,NULL,NULL,NULL)) < 0) {
  478.         if (!locked) unlock_creation();
  479.         return current;
  480.     }
  481.     if (!current) nr = MSDOS_ROOT_INO;
  482.     else {
  483.         if ((prev = raw_scan(dir->i_sb,current,MSDOS_DOTDOT,&zero,NULL,
  484.             NULL,NULL)) < 0) {
  485.             if (!locked) unlock_creation();
  486.             return prev;
  487.         }
  488.         if ((error = raw_scan(dir->i_sb,prev,NULL,¤t,&nr,NULL,
  489.             NULL)) < 0) {
  490.             if (!locked) unlock_creation();
  491.             return error;
  492.         }
  493.     }
  494.     if (!locked) unlock_creation();
  495.     return nr;
  496. }
  497.  
  498.  
  499. /*
  500.  * msdos_subdirs counts the number of sub-directories of dir. It can be run
  501.  * on directories being created.
  502.  */
  503.  
  504. int msdos_subdirs(struct inode *dir)
  505. {
  506.     int count;
  507.  
  508.     count = 0;
  509.     if (dir->i_ino == MSDOS_ROOT_INO)
  510.         (void) raw_scan_root(dir->i_sb,NULL,&count,NULL,NULL,NULL);
  511.     else {
  512.         if (!MSDOS_I(dir)->i_start) return 0; /* in mkdir */
  513.         else (void) raw_scan_nonroot(dir->i_sb,MSDOS_I(dir)->i_start,
  514.             NULL,&count,NULL,NULL,NULL);
  515.     }
  516.     return count;
  517. }
  518.  
  519.  
  520. /*
  521.  * Scans a directory for a given file (name points to its formatted name) or
  522.  * for an empty directory slot (name is NULL). Returns an error code or zero.
  523.  */
  524.  
  525. int msdos_scan(struct inode *dir,char *name,struct buffer_head **res_bh,
  526.     struct msdos_dir_entry **res_de,int *ino)
  527. {
  528.     int res;
  529.  
  530.     if (name)
  531.         res = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,name,NULL,ino,
  532.             res_bh,res_de);
  533.     else res = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,NULL,NULL,ino,
  534.             res_bh,res_de);
  535.     return res < 0 ? res : 0;
  536. }
  537.